/***
* ==++==
*
* Copyright (c) Microsoft Corporation.  All rights reserved.
*
* ==--==
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
*
* agnt_tcp_client.h
*
* C++ Actors: TCP client
*
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
****/

#pragma once

#include "actor_public.h"
#include "comm.h"
#include "pid.h"
#include "procinfo.h"
#include "uri.h"
#include "xxwin32.h"
#include "log.h"

namespace actors
{

/// <summary>
/// Messaging proxy for all outgoing communication with a specific host
/// (Windows process). This class is use entirely by the runtime and has
/// no APIs intended for programmer use.
///
/// PIDs will cache a pointer to an ITarget of the actor that it represents.
/// For locally available actors, it refers to the inbox of the process;
/// for remote actors, it refers to the tcp_proxy instance representing the
/// host containing the process.
/// </summary>
class tcp_proxy : public _IMessageDispatcher, public Serializer
{
public:
    /// <summary>
    /// Constructor
    /// </summary>
    _DISPIMP tcp_proxy(const http::uri &uri);
    _DISPIMP ~tcp_proxy(); 

    /// <summary>
    /// 
    /// </summary>
    virtual bool dispatch(dispatch_msg *msg);

    /// <summary>
    /// 
    /// </summary>
    virtual msg_op get_ack();

    /// <summary>
    /// Write a number of bytes to the underlying socket and 
    /// advance the internal write position.
    /// </summary>
    /// <param name="byteCount">The number of bytes to write</param>
    /// <param name="source">The address of the data block to copy from</param>
    _DISPIMP virtual bool write(size_t byteCount, const void *source);

    /// <summary>
    /// finalize a top-level serialization request
    /// </summary>
    virtual bool flush() { return get_ack() == ACK_OK; }

    /// <summary>
    /// Lock the proxy to avoid concurrent use.
    /// </summary>
    _DISPIMP virtual void lock();

    /// <summary>
    /// Unlock the proxy.
    /// </summary>
    _DISPIMP virtual void unlock();

    virtual bool is_local() const { return false; }

#pragma region "private declarations"
private:
    friend class _actor_info;
    friend class tcp_listener;
    friend class actor;
    friend class PID;

    _DISPIMP friend bool (::deserialize)(PID &pid, actors::Serializer &serializer);

    static IMessageDispatcher _find(const std::string &uri);
    static IMessageDispatcher _clear(const std::string &uri);

    static void _close_all();

    bool _setup();

    bool _start();
    bool _close();

    bool m_closed;
    bool m_started;

    bool m_compress_msgs;
    
    SOCKET m_socket;

    http::uri m_uri;

    PID::Group m_linked_processes;

    static std::hash_map<std::string, IMessageDispatcher> s_proxies;

    actors::details::win32::reentrant_lock m_instance_lock;
    static Concurrency::critical_section s_static_lock;
#pragma endregion
};

} // namespace actors